/**
 * 
 */
package generation;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.uml2.uml.Transition;

import CDPackage.ClassDiagram;
import CDPackage.Clazz;
import CDPackage.Ref;
import names.Names;

/**
 * @author Pratik Bhavsar
 * 
 */
public class GenerationCode {

	private static String output = "src/out/";
	private static String packageOut = "out";

	public static void generateCodeServeur(ClassDiagram diag) {

		// find server
		Clazz server_clazz = null;

		for (Clazz c : diag.getClazzes())
			if (c.getName().equals(Names.serverClassName)) {
				server_clazz = c;
				break;
			}

		if (server_clazz == null) {
			System.out.println(Names.serverClassName + " class not found");
			return;
		}

		PrintWriter serveur = null;
		try {
			serveur = new PrintWriter(output + Names.serverClassName + ".java");
		} catch (FileNotFoundException e2) {
			System.out.println("file not found");
			return;
		}
		serveur.println("package " + packageOut + ";");
		serveur.println("public class " + Names.serverClassName + "{");

		// attributeref
		for (Ref ref : server_clazz.getReferences()) {
			serveur.println("public " + ref.getType().getName() + " "
					+ ref.getName() + ";");
		}

		EList<CDPackage.Operation> operations = diag.getClazzes().get(0)
				.getOperations();

		for (CDPackage.Operation op : operations) {

			serveur.println("public void " + op.getName()
					+ "() throws Exception {");
			serveur.println("state." + op.getName() + "();");
			serveur.println("System.out.println(" + Names.stateFieldName
					+ ".name);");
			serveur.println("}");

		}

		serveur.println("public void setState(State state){");
		serveur.println("this.state = state;");
		serveur.println("}\n}");
		serveur.close();
	}

	public static void generateCodeEtat(ClassDiagram diag) {

		// find state
		Clazz state_clazz = null;

		for (Clazz c : diag.getClazzes())
			if (c.getName().equals(Names.stateClassName)) {
				state_clazz = c;
				break;
			}

		if (state_clazz == null) {
			System.out.println(Names.stateClassName + " class not found");
			return;
		}

		PrintWriter etatFile = null;
		try {
			etatFile = new PrintWriter(output + Names.stateClassName + ".java");
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}
		etatFile.println("package " + packageOut + ";");
		etatFile
				.println("public abstract class " + Names.stateClassName + " {");

		etatFile.println("public String name;");

		// attributeref
		for (Ref ref : state_clazz.getReferences()) {
			etatFile.println("public static " + ref.getType().getName() + " "
					+ ref.getName() + ";");
		}

		EList<CDPackage.Operation> operations = diag.getClazzes().get(0)
				.getOperations();

		for (CDPackage.Operation op : operations) {
			etatFile.println("public abstract void " + op.getName()
					+ "() throws Exception;");
		}

		etatFile.println("public static void set" + Names.serverClassName + "("
				+ Names.serverClassName + " _" + Names.serverFieldName + "){");
		etatFile.println("\t" + Names.serverFieldName + " = _"
				+ Names.serverFieldName + ";");
		etatFile.println("}");

		etatFile.println("}");
		etatFile.close();
	}

	public static void generateCode(ClassDiagram cd, List<EObject> objects) {

		System.out.print("Generation code " + Names.serverClassName + "...");
		// GENERATION CODE SERVEUR
		generateCodeServeur(cd);
		// FIN CODE SERVEUR
		System.out.println("done");

		System.out.print("Generation code State...");
		// GENERER CODE STATE
		generateCodeEtat(cd);
		// FIN CODE STATE
		System.out.println("done");

		for (Clazz c : cd.getClazzes()) {
			if (c.getName().equals(Names.serverClassName))
				continue;
			if (c.getName().equals(Names.stateClassName))
				continue;

			System.out.print("Generation code " + c.getName() + "...");

			PrintWriter fileOpen = null;
			try {
				fileOpen = new PrintWriter(output + Names.stateClassName
						+ c.getName() + ".java");
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			fileOpen.println("package " + packageOut + ";");
			fileOpen.println("public class " + Names.stateClassName
					+ c.getName() + " extends " + Names.stateClassName + "{");

			fileOpen.println("public " + Names.stateClassName + c.getName()
					+ "(String name){");
			fileOpen.println("\tsuper();");
			fileOpen.println("\tthis.name = name;");
			fileOpen.println("}");

			EList<CDPackage.Operation> operations = cd.getClazzes().get(0)
					.getOperations();

			for (CDPackage.Operation op : operations) {

				// chercher le class target
				String target = findTarget(cd, op, c, objects);
				if (target == null) {
					fileOpen.println("public void " + op.getName()
							+ "() throws Exception{");
					fileOpen
							.println("throw new Exception(\"Operation not found\");");
					fileOpen.println("}");
				}

				else {
					fileOpen.println("public void " + op.getName() + "(){");
					fileOpen.println(Names.serverFieldName + ".set"
							+ Names.stateClassName + "(" + "new State" + target
							+ "(\"" + target + "\"));");
					fileOpen.println("}");

				}
			}

			fileOpen.println("}");
			fileOpen.close();

			System.out.println("done");
		}
	}

	public static void generateCodeMain(ClassDiagram cd, List<EObject> objects) {

		EList<CDPackage.Operation> operations = cd.getClazzes().get(0)
				.getOperations();

		PrintWriter fileOpen = null;
		try {
			fileOpen = new PrintWriter(output + "Main.java");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		fileOpen.println("package " + packageOut + ";");
		fileOpen.println("public class Main{");
		fileOpen.println("public static void main(String[] args){");

		for (Clazz c : cd.getClazzes()) {
			if (c.getName().equals("State"))
				continue;

			if (c.getName().equals(Names.serverClassName)) {
				fileOpen.println("\t" + c.getName() + " "
						+ c.getName().toLowerCase() + " = new "
						+ Names.serverClassName + "();");

				continue;
			}

			fileOpen.println("\t" + "State" + c.getName() + " "
					+ c.getName().toLowerCase() + " = new State" + c.getName()
					+ "(\"" + c.getName() + "\");");
		}
		fileOpen.println("\t" + "State.set" + Names.serverClassName + "("
				+ Names.serverFieldName + ");");
		fileOpen.println("\t" + Names.serverFieldName + ".set"
				+ Names.stateClassName + "(start);");

		fileOpen.println("//test1");

		fileOpen.println("\ttry{");
		fileOpen.println("\t\t" + Names.serverFieldName + ".open();");
		fileOpen.println("\t\t" + Names.serverFieldName + ".close();");
		fileOpen.println("\t\t" + Names.serverFieldName + ".lock();");
		fileOpen.println("\t\t" + Names.serverFieldName + ".unlock();");
		fileOpen.println("\t\t" + Names.serverFieldName + ".end();");
		fileOpen.println("\t}catch(Exception e){");
		fileOpen.println("\t\tSystem.out.println(e);");
		fileOpen.println("\t}");

		fileOpen.println("\t}\n}");
		fileOpen.close();

		System.out.println("done");

	}

	/**
	 * 
	 * @param cd
	 *            Diagramme de classe
	 * @param op
	 *            Operation
	 * @param c
	 *            Clazz source de op
	 * @param objects
	 *            liste d'EObjects � partir du diagramme d'activit�
	 * @return String target
	 */
	public static String findTarget(ClassDiagram cd, CDPackage.Operation op,
			Clazz c, List<EObject> objects) {
		ArrayList<Transition> transitions = new ArrayList<Transition>();

		for (EObject eo : objects)
			if (eo instanceof Transition)
				transitions.add((Transition) eo);

		for (Transition tr : transitions)
			if (tr.getName().equals(op.getName())
					&& (tr.getSource().getName().equals(c.getName()))) {
				return tr.getTarget().getName();
			}

		return null;
	}

}
